/*
 * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
 *
 * This software is provided 'as-is', without any express or implied
 * warranty.  In no event will the authors be held liable for any damages
 * arising from the use of this software.
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 * 1. The origin of this software must not be misrepresented; you must not
 * claim that you wrote the original software. If you use this software
 * in a product, an acknowledgment in the product documentation would be
 * appreciated but is not required.
 * 2. Altered source versions must be plainly marked as such, and must not be
 * misrepresented as being the original software.
 * 3. This notice may not be removed or altered from any source distribution.
 */

package org.box2dflash.dynamics {
	import org.box2dflash.dynamics.*;
	import org.box2dflash.dynamics.joints.*;
	import org.box2dflash.dynamics.contacts.*;
	import org.box2dflash.collision.shapes.*;
	import org.box2dflash.common.math.*;
	import org.box2dflash.common.*;
	use namespace Internal;

	/// A rigid body.
	public class Body {
		/// Creates a shape and attach it to this body.
		/// @param shapeDef the shape definition.
		/// @warning This function is locked during callbacks.
		public function createShape(def:ShapeDef):Shape {
			//Settings.Assert(m_world.m_lock == false);
			if (m_world.m_lock == true) {
				return null;
			}
		
			var s:Shape = Shape.create(def/*NOT USED, m_world.m_blockAllocator*/);
		
			s.m_next = m_shapeList;
			m_shapeList = s;
			++m_shapeCount;
		
			s.m_body = this;
		
			// Add the shape to the world's broad-phase.
			s.createProxy(m_world.m_broadPhase, m_xf);
		
			// Compute the sweep radius for CCD.
			s.updateSweepRadius(m_sweep.localCenter);
		
			return s;
		}

		/// Destroy a shape. This removes the shape from the broad-phase and
		/// therefore destroys any contacts associated with this shape. All shapes
		/// attached to a body are implicitly destroyed when the body is destroyed.
		/// @param shape the shape to be removed.
		/// @warning This function is locked during callbacks.
		public function destroyShape(s:Shape):void {
			//Settings.Assert(m_world.m_lock == false);
			if (m_world.m_lock == true) {
				return;
			}
		
			//Settings.Assert(s.m_body == this);
			s.destroyProxy(m_world.m_broadPhase);
		
			//Settings.Assert(m_shapeCount > 0);
			//Shape** node = &m_shapeList;
			var node:Shape = m_shapeList;
			var found:Boolean = false;
			while (node != null) {
				if (node == s) {
					node = s.m_next;
					found = true;
					break;
				}
			
				node = node.m_next;
			}
		
			// You tried to remove a shape that is not attached to this body.
			//Settings.Assert(found);
			s.m_body = null;
			s.m_next = null;
		
			--m_shapeCount;
		
			Shape.destroy(s/*NOT USED, m_blockAllocator*/);
		}

		/// Set the mass properties. Note that this changes the center of mass position.
		/// If you are not sure how to compute mass properties, use SetMassFromShapes.
		/// The inertia tensor is assumed to be relative to the center of mass.
		/// @param massData the mass properties.
		public function setMass(massData:MassData):void {
			var s:Shape;
		
			//Settings.Assert(m_world.m_lock == false);
			if (m_world.m_lock == true) {
				return;
			}
		
			m_invMass = 0.0;
			m_I = 0.0;
			m_invI = 0.0;
		
			m_mass = massData.mass;
		
			if (m_mass > 0.0) {
				m_invMass = 1.0 / m_mass;
			}
		
			if ((m_flags & Body.e_fixedRotationFlag) == 0) {
				m_I = massData.I;
			}
		
			if (m_I > 0.0) {
				m_invI = 1.0 / m_I;
			}
		
			// Move center of mass.
			m_sweep.localCenter.v(massData.center);
			//m_sweep.c0 = m_sweep.c = Mul(m_xf, m_sweep.localCenter);
			//MulMV(m_xf.R, m_sweep.localCenter);
			var tMat:Mat22 = m_xf.R;
			var tVec:Vec2 = m_sweep.localCenter;
			// (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y)
			m_sweep.c.x = (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y);
			// (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y)
			m_sweep.c.y = (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y);
			//return T.position + Mul(T.R, v);
			m_sweep.c.x += m_xf.position.x;
			m_sweep.c.y += m_xf.position.y;
			//m_sweep.c0 = m_sweep.c
			m_sweep.c0.v(m_sweep.c);
		
			// Update the sweep radii of all child shapes.
			for (s = m_shapeList;s; s = s.m_next) {
				s.updateSweepRadius(m_sweep.localCenter);
			}

			var oldType:int = m_type;
			if (m_invMass == 0.0 && m_invI == 0.0) {
				m_type = e_staticType;
			}
		else {
				m_type = e_dynamicType;
			}
	
			// If the body type changed, we need to refilter the broad-phase proxies.
			if (oldType != m_type) {
				for (s = m_shapeList;s; s = s.m_next) {
					s.refilterProxy(m_world.m_broadPhase, m_xf);
				}
			}
		}

		/// Compute the mass properties from the attached shapes. You typically call this
		/// after adding all the shapes. If you add or remove shapes later, you may want
		/// to call this again. Note that this changes the center of mass position.
		static private var s_massData:MassData = new MassData();

		public function setMassFromShapes():void {
		
			var s:Shape;
		
			//Settings.Assert(m_world.m_lock == false);
			if (m_world.m_lock == true) {
				return;
			}
		
			// Compute mass data from shapes. Each shape has its own density.
			m_mass = 0.0;
			m_invMass = 0.0;
			m_I = 0.0;
			m_invI = 0.0;
		
			//Vec2 center = Vec2_zero;
			var centerX:Number = 0.0;
			var centerY:Number = 0.0;
			var massData:MassData = s_massData;
			for (s = m_shapeList;s; s = s.m_next) {
				s.computeMass(massData);
				m_mass += massData.mass;
				//center += massData.mass * massData.center;
				centerX += massData.mass * massData.center.x;
				centerY += massData.mass * massData.center.y;
				m_I += massData.I;
			}
		
			// Compute center of mass, and shift the origin to the COM.
			if (m_mass > 0.0) {
				m_invMass = 1.0 / m_mass;
				centerX *= m_invMass;
				centerY *= m_invMass;
			}
		
			if (m_I > 0.0 && (m_flags & e_fixedRotationFlag) == 0) {
				// Center the inertia about the center of mass.
				//m_I -= m_mass * Dot(center, center);
				m_I -= m_mass * (centerX * centerX + centerY * centerY);
				//Settings.Assert(m_I > 0.0);
				m_invI = 1.0 / m_I;
			}
		else {
				m_I = 0.0;
				m_invI = 0.0;
			}
		
			// Move center of mass.
			m_sweep.localCenter = new Vec2(centerX, centerY);
			//m_sweep.c0 = m_sweep.c = Mul(m_xf, m_sweep.localCenter);
			//MulMV(m_xf.R, m_sweep.localCenter);
			var tMat:Mat22 = m_xf.R;
			var tVec:Vec2 = m_sweep.localCenter;
			// (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y)
			m_sweep.c.x = (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y);
			// (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y)
			m_sweep.c.y = (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y);
			//return T.position + Mul(T.R, v);
			m_sweep.c.x += m_xf.position.x;
			m_sweep.c.y += m_xf.position.y;
			//m_sweep.c0 = m_sweep.c
			m_sweep.c0.v(m_sweep.c);
		
			// Update the sweep radii of all child shapes.
			for (s = m_shapeList;s; s = s.m_next) {
				s.updateSweepRadius(m_sweep.localCenter);
			}
		
			var oldType:int = m_type;
			if (m_invMass == 0.0 && m_invI == 0.0) {
				m_type = e_staticType;
			}
		else {
				m_type = e_dynamicType;
			}
		
			// If the body type changed, we need to refilter the broad-phase proxies.
			if (oldType != m_type) {
				for (s = m_shapeList;s; s = s.m_next) {
					s.refilterProxy(m_world.m_broadPhase, m_xf);
				}
			}
		}

		/// Set the position of the body's origin and rotation (radians).
		/// This breaks any contacts and wakes the other bodies.
		/// @param position the new world position of the body's origin (not necessarily
		/// the center of mass).
		/// @param angle the new world rotation angle of the body in radians.
		/// @return false if the movement put a shape outside the world. In this case the
		/// body is automatically frozen.
		public function xForm(position:Vec2, angle:Number):Boolean {
		
			var s:Shape;
		
			//Settings.Assert(m_world.m_lock == false);
			if (m_world.m_lock == true) {
				return true;
			}
		
			if (isFrozen) {
				return false;
			}
		
			m_xf.R = new Mat22(angle);
			m_xf.position.v(position);
		
			//m_sweep.c0 = m_sweep.c = Mul(m_xf, m_sweep.localCenter);
			//MulMV(m_xf.R, m_sweep.localCenter);
			var tMat:Mat22 = m_xf.R;
			var tVec:Vec2 = m_sweep.localCenter;
			// (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y)
			m_sweep.c.x = (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y);
			// (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y)
			m_sweep.c.y = (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y);
			//return T.position + Mul(T.R, v);
			m_sweep.c.x += m_xf.position.x;
			m_sweep.c.y += m_xf.position.y;
			//m_sweep.c0 = m_sweep.c
			m_sweep.c0.v(m_sweep.c);
		
			m_sweep.a0 = m_sweep.a = angle;
		
			var freeze:Boolean = false;
			for (s = m_shapeList;s; s = s.m_next) {
				var inRange:Boolean = s.synchronize(m_world.m_broadPhase, m_xf, m_xf);
			
				if (inRange == false) {
					freeze = true;
					break;
				}
			}
		
			if (freeze == true) {
				m_flags |= e_frozenFlag;
				m_linearVelocity.zero();
				m_angularVelocity = 0.0;
				for (s = m_shapeList;s; s = s.m_next) {
					s.destroyProxy(m_world.m_broadPhase);
				}
			
				// Failure
				return false;
			}
		
			// Success
			m_world.m_broadPhase.commit();
			return true;
		}

		/// Get the body transform for the body's origin.
		/// @return the world transform of the body's origin.
		public function getXForm():XForm {
			return m_xf;
		}

		/// Get the world body origin position.
		/// @return the world position of the body's origin.
		public function get position():Vec2 {
			return m_xf.position;
		}

		/// Get the angle in radians.
		/// @return the current world rotation angle in radians.
		public function get angle():Number {
			return m_sweep.a;
		}

		/// Get the world position of the center of mass.
		public function get worldCenter():Vec2 {
			return m_sweep.c;
		}

		/// Get the local position of the center of mass.
		public function get localCenter():Vec2 {
			return m_sweep.localCenter;
		}

		/// Set the linear velocity of the center of mass.
		/// @param v the new linear velocity of the center of mass.
		public function set linearVelocity(v:Vec2):void {
			m_linearVelocity.v(v);
		}

		/// Get the linear velocity of the center of mass.
		/// @return the linear velocity of the center of mass.
		public function get linearVelocity():Vec2 {
			return m_linearVelocity;
		}

		/// Set the angular velocity.
		/// @param omega the new angular velocity in radians/second.
		public function set angularVelocity(omega:Number):void {
			m_angularVelocity = omega;
		}

		/// Get the angular velocity.
		/// @return the angular velocity in radians/second.
		public function get angularVelocity():Number {
			return m_angularVelocity;
		}

		/// Apply a force at a world point. If the force is not
		/// applied at the center of mass, it will generate a torque and
		/// affect the angular velocity. This wakes up the body.
		/// @param force the world force vector, usually in Newtons (N).
		/// @param point the world position of the point of application.
		public function applyForce(force:Vec2, point:Vec2):void {
			if (isSleeping) {
				wakeUp();
			}
			//m_force += force;
			m_force.x += force.x;
			m_force.y += force.y;
			//m_torque += Cross(point - m_sweep.c, force);
			m_torque += ((point.x - m_sweep.c.x) * force.y - (point.y - m_sweep.c.y) * force.x);
		}

		/// Apply a torque. This affects the angular velocity
		/// without affecting the linear velocity of the center of mass.
		/// This wakes up the body.
		/// @param torque about the z-axis (out of the screen), usually in N-m.
		public function applyTorque(torque:Number):void {
			if (isSleeping) {
				wakeUp();
			}
			m_torque += torque;
		}

		/// Apply an impulse at a point. This immediately modifies the velocity.
		/// It also modifies the angular velocity if the point of application
		/// is not at the center of mass. This wakes up the body.
		/// @param impulse the world impulse vector, usually in N-seconds or kg-m/s.
		/// @param point the world position of the point of application.
		public function applyImpulse(impulse:Vec2, point:Vec2):void {
			if (isSleeping) {
				wakeUp();
			}
			//m_linearVelocity += m_invMass * impulse;
			m_linearVelocity.x += m_invMass * impulse.x;
			m_linearVelocity.y += m_invMass * impulse.y;
			//m_angularVelocity += m_invI * Cross(point - m_sweep.c, impulse);
			m_angularVelocity += m_invI * ((point.x - m_sweep.c.x) * impulse.y - (point.y - m_sweep.c.y) * impulse.x);
		}

		/// Get the total mass of the body.
		/// @return the mass, usually in kilograms (kg).
		public function get mass():Number {
			return m_mass;
		}

		/// Get the central rotational inertia of the body.
		/// @return the rotational inertia, usually in kg-m^2.
		public function get inertia():Number {
			return m_I;
		}

		/// Get the world coordinates of a point given the local coordinates.
		/// @param localPoint a point on the body measured relative the the body's origin.
		/// @return the same point expressed in world coordinates.
		public function worldPoint(localPoint:Vec2):Vec2 {
			//return Box2dMath.MulX(m_xf, localPoint);
			var A:Mat22 = m_xf.R;
			var u:Vec2 = new Vec2(A.col1.x * localPoint.x + A.col2.x * localPoint.y, A.col1.y * localPoint.x + A.col2.y * localPoint.y);
			u.x += m_xf.position.x;
			u.y += m_xf.position.y;
			return u;
		}

		/// Get the world coordinates of a vector given the local coordinates.
		/// @param localVector a vector fixed in the body.
		/// @return the same vector expressed in world coordinates.
		public function worldVector(localVector:Vec2):Vec2 {
			return Box2dMath.mulMV(m_xf.R, localVector);
		}

		/// Gets a local point relative to the body's origin given a world point.
		/// @param a point in world coordinates.
		/// @return the corresponding local point relative to the body's origin.
		public function localPoint(worldPoint:Vec2):Vec2 {
			return Box2dMath.mulXT(m_xf, worldPoint);
		}

		/// Gets a local vector given a world vector.
		/// @param a vector in world coordinates.
		/// @return the corresponding local vector.
		public function localVector(worldVector:Vec2):Vec2 {
			return Box2dMath.mulTMV(m_xf.R, worldVector);
		}

		/// Get the world linear velocity of a world point attached to this body.
		/// @param a point in world coordinates.
		/// @return the world velocity of a point.
		public function linearVelocityFromWorldPoint(worldPoint:Vec2):Vec2 {
			//return          m_linearVelocity   + Cross(m_angularVelocity,   worldPoint   - m_sweep.c);
			return new Vec2(m_linearVelocity.x + m_angularVelocity * (worldPoint.y - m_sweep.c.y), m_linearVelocity.x - m_angularVelocity * (worldPoint.x - m_sweep.c.x));
		}

		/// Get the world velocity of a local point.
		/// @param a point in local coordinates.
		/// @return the world velocity of a point.
		public function linearVelocityFromLocalPoint(localPoint:Vec2):Vec2 {
			//return GetLinearVelocityFromWorldPoint(worldPoint(localPoint));
			var A:Mat22 = m_xf.R;
			var worldPoint:Vec2 = new Vec2(A.col1.x * localPoint.x + A.col2.x * localPoint.y, A.col1.y * localPoint.x + A.col2.y * localPoint.y);
			worldPoint.x += m_xf.position.x;
			worldPoint.y += m_xf.position.y;
			return new Vec2(m_linearVelocity.x + m_angularVelocity * (worldPoint.y - m_sweep.c.y), m_linearVelocity.x - m_angularVelocity * (worldPoint.x - m_sweep.c.x));
		}

		/// Is this body treated like a bullet for continuous collision detection?
		public function get isBullet():Boolean {
			return (m_flags & e_bulletFlag) == e_bulletFlag;
		}

		/// Should this body be treated like a bullet for continuous collision detection?
		public function set isBullet(flag:Boolean):void {
			if (flag) {
				m_flags |= e_bulletFlag;
			}
		else {
				m_flags &= ~e_bulletFlag;
			}
		}

		/// Is this body static (immovable)?
		public function get isStatic():Boolean {
			return m_type == e_staticType;
		}

		/// Is this body dynamic (movable)?
		public function get isDynamic():Boolean {
			return m_type == e_dynamicType;
		}

		/// Is this body frozen?
		public function get isFrozen():Boolean {
			return (m_flags & e_frozenFlag) == e_frozenFlag;
		}

		/// Is this body sleeping (not simulating).
		public function get isSleeping():Boolean {
			return (m_flags & e_sleepFlag) == e_sleepFlag;
		}

		/// You can disable sleeping on this body.
		public function allowSleeping(flag:Boolean):void {
			if (flag) {
				m_flags |= e_allowSleepFlag;
			}
		else {
				m_flags &= ~e_allowSleepFlag;
				wakeUp();
			}
		}

		/// Wake up this body so it will begin simulating.
		public function wakeUp():void {
			m_flags &= ~e_sleepFlag;
			m_sleepTime = 0.0;
		}

		/// Put this body to sleep so it will stop simulating.
		/// This also sets the velocity to zero.
		public function putToSleep():void {
			m_flags |= e_sleepFlag;
			m_sleepTime = 0.0;
			m_linearVelocity.zero();
			m_angularVelocity = 0.0;
			m_force.zero();
			m_torque = 0.0;
		}

		/// Get the list of all shapes attached to this body.
		public function get shapeList():Shape {
			return m_shapeList;
		}

		/// Get the list of all joints attached to this body.
		public function get jointList():JointEdge {
			return m_jointList;
		}

		/// Get the next body in the world's body list.
		public function get next():Body {
			return m_next;
		}

		/// Get the user data pointer that was provided in the body definition.
		public function get userData():* {
			return m_userData;
		}

		/// Set the user data. Use this to store your application specific data.
		public function set userData(data:*):void {
			m_userData = data;
		}

		/// Get the parent world of this body.
		public function get world():World {
			return m_world;
		}

		//--------------- Internals Below -------------------

	
		// Constructor
		public function Body(bd:BodyDef, world:World) {
			//Settings.Assert(world.m_lock == false);
			m_flags = 0;
		
			if (bd.isBullet) {
				m_flags |= e_bulletFlag;
			}
			if (bd.fixedRotation) {
				m_flags |= e_fixedRotationFlag;
			}
			if (bd.allowSleep) {
				m_flags |= e_allowSleepFlag;
			}
			if (bd.isSleeping) {
				m_flags |= e_sleepFlag;
			}
		
			m_world = world;
		
			m_xf.position.v(bd.position);
			m_xf.R = new Mat22(bd.angle);
		
			m_sweep.localCenter.v(bd.massData.center);
			m_sweep.t0 = 1.0;
			m_sweep.a0 = m_sweep.a = bd.angle;
		
			//m_sweep.c0 = m_sweep.c = Mul(m_xf, m_sweep.localCenter);
			//MulMV(m_xf.R, m_sweep.localCenter);
			var tMat:Mat22 = m_xf.R;
			var tVec:Vec2 = m_sweep.localCenter;
			// (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y)
			m_sweep.c.x = (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y);
			// (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y)
			m_sweep.c.y = (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y);
			//return T.position + Mul(T.R, v);
			m_sweep.c.x += m_xf.position.x;
			m_sweep.c.y += m_xf.position.y;
			//m_sweep.c0 = m_sweep.c
			m_sweep.c0.v(m_sweep.c);
		
			m_jointList = null;
			m_contactList = null;
			m_prev = null;
			m_next = null;
		
			m_linearDamping = bd.linearDamping;
			m_angularDamping = bd.angularDamping;
		
			m_force = new Vec2(0.0, 0.0);
			m_torque = 0.0;
		
			m_linearVelocity.zero();
			m_angularVelocity = 0.0;
		
			m_sleepTime = 0.0;
		
			m_invMass = 0.0;
			m_I = 0.0;
			m_invI = 0.0;
		
			m_mass = bd.massData.mass;
		
			if (m_mass > 0.0) {
				m_invMass = 1.0 / m_mass;
			}
		
			if ((m_flags & Body.e_fixedRotationFlag) == 0) {
				m_I = bd.massData.I;
			}
		
			if (m_I > 0.0) {
				m_invI = 1.0 / m_I;
			}
		
			if (m_invMass == 0.0 && m_invI == 0.0) {
				m_type = e_staticType;
			}
		else {
				m_type = e_dynamicType;
			}
	
			m_userData = bd.userData;
		
			m_shapeList = null;
			m_shapeCount = 0;
		}

		// Destructor
		//~Body();

		//
		static private var s_xf1:XForm = new XForm();

		//
		Internal function synchronizeShapes():Boolean {
		
			var xf1:XForm = s_xf1;
			xf1.R = new Mat22(m_sweep.a0);
			//xf1.position = m_sweep.c0 - Mul(xf1.R, m_sweep.localCenter);
			var tMat:Mat22 = xf1.R;
			var tVec:Vec2 = m_sweep.localCenter;
			xf1.position.x = m_sweep.c0.x - (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y);
			xf1.position.y = m_sweep.c0.y - (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y);
		
			var s:Shape;
		
			var inRange:Boolean = true;
			for (s = m_shapeList;s; s = s.m_next) {
				inRange = s.synchronize(m_world.m_broadPhase, xf1, m_xf);
				if (inRange == false) {
					break;
				}
			}
		
			if (inRange == false) {
				m_flags |= e_frozenFlag;
				m_linearVelocity.zero();
				m_angularVelocity = 0.0;
				for (s = m_shapeList;s; s = s.m_next) {
					s.destroyProxy(m_world.m_broadPhase);
				}
			
				// Failure
				return false;
			}
		
			// Success
			return true;
		}

		Internal function synchronizeTransform():void {
			m_xf.R = new Mat22(m_sweep.a);
			//m_xf.position = m_sweep.c - Mul(m_xf.R, m_sweep.localCenter);
			var tMat:Mat22 = m_xf.R;
			var tVec:Vec2 = m_sweep.localCenter;
			m_xf.position.x = m_sweep.c.x - (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y);
			m_xf.position.y = m_sweep.c.y - (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y);
		}

		// This is used to prevent connected bodies from colliding.
		// It may lie, depending on the collideConnected flag.
		Internal function IsConnected(other:Body):Boolean {
			for (var jn:JointEdge = m_jointList;jn; jn = jn.next) {
				if (jn.other == other)
				return jn.joint.m_collideConnected == false;
			}
		
			return false;
		}

		Internal function advance(t:Number):void {
			// Advance to the new safe time.
			m_sweep.advance(t);
			m_sweep.c.v(m_sweep.c0);
			m_sweep.a = m_sweep.a0;
			synchronizeTransform();
		}

		Internal var m_flags:uint;
		Internal var m_type:int;
		Internal var m_xf:XForm = new XForm();		
		// the body origin transform
		Internal var m_sweep:Sweep = new Sweep();	
		// the swept motion for CCD
		Internal var m_linearVelocity:Vec2 = new Vec2();
		Internal var m_angularVelocity:Number;
		Internal var m_force:Vec2 = new Vec2();
		Internal var m_torque:Number;
		Internal var m_world:World;
		Internal var m_prev:Body;
		Internal var m_next:Body;
		Internal var m_shapeList:Shape;
		Internal var m_shapeCount:int;
		Internal var m_jointList:JointEdge;
		Internal var m_contactList:ContactEdge;
		Internal var m_mass:Number, m_invMass:Number;
		Internal var m_I:Number, m_invI:Number;
		Internal var m_linearDamping:Number;
		Internal var m_angularDamping:Number;
		Internal var m_sleepTime:Number;
		Internal var m_userData:*;
		// m_flags
		//enum
		//{
		static Internal var e_frozenFlag:uint = 0x0002;
		static Internal var e_islandFlag:uint = 0x0004;
		static Internal var e_sleepFlag:uint = 0x0008;
		static Internal var e_allowSleepFlag:uint = 0x0010;
		static Internal var e_bulletFlag:uint = 0x0020;
		static Internal var e_fixedRotationFlag:uint = 0x0040;
		//};

		// m_type
		//enum
		//{
		static Internal var e_staticType:uint = 1;
		static Internal var e_dynamicType:uint = 2;
		static Internal var e_maxTypes:uint = 3;
	//};
	}
}
